pandas write to excel example とContetxt manager

to excel

import pandas as pd
import numpy as np


writer = pd.ExcelWriter("excel_file_path.xlsx")

df = pd.DataFrame(np.random.randn(50, 2), columns=list('ab'))
df.to_excel(writer, sheet_name="sheet_name1", index=False)
df.to_excel(writer, sheet_name="sheet_name2", index=False)

writer.save()
  • 使うだけならここまででよかったんだけど
  • ioが絡むのになんでcontext managerが一切出てこないのかな?と思い調べてみた。
  • 結果withと一緒に使えるので、使おう。勝手にsaveされるようにもなる
with pd.ExcelWriter("excel_file_path.xlsx") as witer:
    df.to_excel(writer, sheet_name="sheet_name1", index=False)
    df.to_excel(writer, sheet_name="sheet_name2", index=False)

以下調査過程

enter and exit

help(writer.__exit__)
Help on method __exit__ in module pandas.io.excel:
__exit__(exc_type, exc_value, traceback) method of pandas.io.excel._XlsxWriter instance


help(writer.__enter__)
Help on method __enter__ in module pandas.io.excel:
__enter__() method of pandas.io.excel._XlsxWriter instance
    # Allow use as a contextmanager


[a for a in dir(writer) if not a.startswith('_')]
['book',
 'check_extension',
 'close',
 'cur_sheet',
 'curr_sheet',
 'date_format',
 'datetime_format',
 'engine',
 'path',
 'save',
 'sheets',
 'supported_extensions',
 'write_cells']

pandas excel module and base excel module

  • 抜粋
  • 抽象クラスとxlsx実装クラスがある
  • 抽象クラス内でcontext managerとしてのInterfaceが決めてある
  • 実装クラス内でsave実装
  • 実際はimportしているmoduleにまかせている
  • 最終的にはzipファイルcloseしているが、ここではwithがない…
# pandas/io/excel.py
@add_metaclass(abc.ABCMeta)
class ExcelWriter(object):
    @abc.abstractmethod
    def save(self):
        pass

    # Allow use as a contextmanager
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()

    def close(self):
        """synonym for save, to make it more file-like"""
        return self.save()

class _XlsxWriter(ExcelWriter):
    def __init__(self, ):
        # Use the xlsxwriter module as the Excel writer.
        import xlsxwriter
        # https://pypi.python.org/pypi/XlsxWriter
        # https://github.com/jmcnamara/XlsxWriter

        super(_XlsxWriter, self).__init__
        self.book = xlsxwriter.Workbook(path, **engine_kwargs)

    def save(self):
        """
        Save workbook to disk.
        """
        return self.book.close()

# xlsxwriter/__init__.py
from .workbook import Workbook

# xlsxwriter/workbook.py
class Workbook(xmlwriter.XMLwriter):
    def __enter__(self):
        """Return self object to use with "with" statement."""
        return self

    def __exit__(self, type, value, traceback):
        """Close workbook when exiting "with" statement."""
        self.close()

    def close(self):
        """
        Call finalization code and close file.
        Args:
            None.
        Returns:
            Nothing.
        """
        if not self.fileclosed:
            self.fileclosed = 1
            self._store_workbook()

    def _store_workbook(self):
        xlsx_file = ZipFile(self.filename, "w", compression=ZIP_DEFLATED,
                            allowZip64=self.allow_zip64)
        xlsx_file.close()